筆記目錄

Skip to content

淺談 Entity Framework 中的預設值行為

TLDR

  • 當 SQL Server 欄位設有預設值時,若 Entity 屬性值與該型別的 C# 預設值一致,EF Core 在執行 INSERT 時可能會忽略該欄位。
  • 建議盡量避免依賴 SQL 預設值,若必須使用,應確保 SQL 預設值與 C# 預設值一致。
  • 字串型別建議設為 NOT NULL Default '' 以統一處理空值與空字串。
  • 當更新 Entity 屬性但值未變更時,SaveChanges() 會回傳 0,判斷邏輯應改為 context.Entry(entity).State == EntityState.Unchanged || context.SaveChanges() > 0
  • 避免在需要更新的場景使用 AsNoTracking(),若使用後手動將狀態設為 EntityState.Modified,會導致該 Entity 所有欄位皆被更新。

Entity Framework 的預設值寫入行為

什麼情況下會遇到這個問題:當資料庫欄位設定了 DEFAULT 約束,且開發者在程式碼中未明確賦值(或賦予與 C# 預設值相同的值)時。

測試發現,Entity Framework 並非根據屬性是否有「設值」行為來判定異動,而是透過比對「新舊值」來決定是否將欄位納入 INSERT 語法。當屬性值與該型別的預設值(如 null0)一致時,EF Core 可能會直接忽略該欄位,交由資料庫處理預設值。

WARNING

若使用 EF Core Power Tools 進行反向工程,針對 bit 等特定型別,可能會因產生的 Entity 屬性型別(如 bool?)與 Required 設定不同,導致 INSERT 語法完全忽略該欄位,進而觸發資料庫的預設值機制。

更新 Entity 但值不變的判斷邏輯

什麼情況下會遇到這個問題:在更新操作中,若 Entity 的屬性值與資料庫現有值相同,但開發者仍執行了 SaveChanges()

當執行更新時,若屬性值未改變,EF Core 會將 EntityState 維持在 Unchanged,此時 SaveChanges() 不會執行任何 UPDATE 指令並回傳 0

建議做法: 在 Business Service 的更新邏輯中,應考量 Unchanged 的狀態,避免誤判更新失敗:

csharp
int changedCount = context.SaveChanges();
bool isSuccess = context.Entry(entity).State == EntityState.Unchanged || changedCount > 0;

AsNoTracking 與 EntityState.Modified 的副作用

什麼情況下會遇到這個問題:在需要更新資料的場景中,誤用了 AsNoTracking() 查詢,隨後為了強行更新而手動將狀態設為 EntityState.Modified

使用 AsNoTracking() 查詢出的 Entity 不受 Change Tracker 管理,若手動將其狀態設為 EntityState.Modified,EF Core 將無法追蹤哪些欄位真正發生了變更,導致產生的 UPDATE 語法會包含資料表中的「所有欄位」,而非僅是變更的欄位。

建議做法:

  • 若需進行更新操作,請勿使用 AsNoTracking()
  • 僅在純粹的唯讀查詢場景中使用 AsNoTracking() 以提升效能。

異動歷程

  • 2025-07-12 初版文件建立。